<template>
    <div style="width: 30px; margin: 0 auto">
        <el-popover placement="right" :width="400" trigger="click" :hide-after="0">
            <template #reference>
                <component is="PlusCircleOutlined" class="plusClass" ref="currentPlus"/>
            </template>
            <el-row :gutter="20">
                <el-col :span="8" class="colSpanClass" @click="addNode('YwuExecutorNode')"><span ><component is="UserOutlined"/> 执行人</span></el-col>
                <el-col :span="8" class="colSpanClass" @click="addNode('YwuApprovalNode')"><span ><component is="UserOutlined"/> 审批人</span></el-col>
                <el-col :span="8" class="colSpanClass" @click="addNode('YwuServiceNode')"><span ><component is="DatabaseOutlined"/> 服务节点</span></el-col>
            </el-row>

            <el-row :gutter="20">
                <el-col :span="8" class="colSpanClass" @click="addNode('YwuConditionalNode')"><span ><component is="ApartmentOutlined"/> 条件分支</span></el-col>
                <el-col :span="8" class="colSpanClass" @click="addNode('YwuParallelNode')"><span ><component is="BranchesOutlined"/> 并行分支</span></el-col>
            </el-row>
        </el-popover>
    </div>

    <div style="height: 30px"></div>

    <div style="width: 150px; margin: 0 auto" ref="currentDiv" @click="showDrawer()" @mouseenter="mouseEnter()" @mouseleave="mouseLeave()">
        <div class="parallelClass" ref="childRef">
            <div class="innerClass" style="padding-top: 10px;position: relative;">
                <component is="CloseCircleOutlined" class="closeClass" v-if="closeShow" @click="deleteNode()"/>
                <component is="BranchesOutlined"/>
                <span class="spanClass">{{jsonInfo.name}}</span>
                <span class="spanNameClass">{{jsonInfo.properties.name}}</span>
            </div>
        </div>
    </div>

    <div style="height: 30px"></div>

    <div style="width: 30px; margin: 0 auto">
        <component is="PlusCircleOutlined" class="plusClass" ref="addChildNodePlus" @click="addChildNodePlus()"/>
    </div>

    <div style="height: 60px"></div>

    <div :style="calcChildrenWidth">
        <div v-for="(item, index) in jsonInfo.childrenNodes" :key="index" style=" display: inline-block;vertical-align: top;" :style="index !== 0 ? 'margin-left: 100px;' : ''">
            <div style="margin: 0 auto; width: 150px">
                <div class="parallelItemClass" :ref="'childNode' + index" :id="'childNode' + index" @mouseenter="conditionMouseEnter(item, index)" @mouseleave="conditionMouseLeave(item)">
                    <div class="innerClass" style="padding-top: 10px;position: relative;">
                        <component is="CloseCircleOutlined" class="closeClass" v-if="item.isShow" @click="deleteCondition(item, index)"/>
                        <component is="BranchesOutlined"/>
                        <span class="spanClass">{{item.conditionName}}</span>
                    </div>
                </div>
            </div>
            <svg width="100000px" height="100000px" style="position: absolute;z-index: -1; top: 0; left: 0;">
                <line :x1="currentChildListTopX[index]"
                      :y1="currentChildListTopY[index] - 40"
                      :x2="currentChildListTopX[index]"
                      :y2="currentChildListTopY[index] - 10"
                      stroke="#000" stroke-width="2" marker-end="url(#arrow)" />
            </svg>
            <div style="height: 30px"></div>

            <component v-if="item.next && item.next !== null" :is="item.next['type']" :jsonInfo="item.next" :beforeNode="item" :ref="'childComponentRef' + index"
                       :beforeNodeStartX="currentChildListBottomX[index]" :beforeNodeStartY="currentChildListBottomY[index]" :globalJson="globalJson"></component>

            <div style="width: 30px; margin: 0 auto;">
                <el-popover placement="right" :width="400" trigger="click" :hide-after="0">
                    <template #reference>
                        <component is="PlusCircleOutlined" class="plusClass" :ref="'conditionLastPlus' + index"/>
                    </template>
                    <el-row :gutter="20">
                        <el-col :span="8" class="colSpanClass" @click="addChildItemNodePlus('YwuExecutorNode', item)"><span ><component is="UserOutlined"/> 执行人</span></el-col>
                        <el-col :span="8" class="colSpanClass" @click="addChildItemNodePlus('YwuApprovalNode', item)"><span ><component is="UserOutlined"/> 审批人</span></el-col>
                        <el-col :span="8" class="colSpanClass" @click="addChildItemNodePlus('YwuServiceNode', item)"><span ><component is="DatabaseOutlined"/> 服务节点</span></el-col>
                    </el-row>

                    <el-row :gutter="20">
                        <el-col :span="8" class="colSpanClass" @click="addChildItemNodePlus('YwuConditionalNode', item)"><span ><component is="ApartmentOutlined"/> 条件分支</span></el-col>
                        <el-col :span="8" class="colSpanClass" @click="addChildItemNodePlus('YwuParallelNode', item)"><span ><component is="BranchesOutlined"/> 并行分支</span></el-col>
                    </el-row>
                </el-popover>
            </div>

            <svg width="100000px" height="100000px" style="position: absolute;z-index: -1; top: 0; left: 0;">
                <line :x1="lastComponentBottomX[index]"
                      :y1="lastComponentBottomY[index]"
                      :x2="conditionLastPlusTopX[index]"
                      :y2="conditionLastPlusTopY[index]"
                      stroke="#000" stroke-width="2" />
            </svg>
            <svg width="100000px" height="100000px" style="position: absolute;z-index: -1; top: 0; left: 0;">
                <line :x1="conditionLastPlusBottomX[index]"
                      :y1="conditionLastPlusBottomY[index]"
                      :x2="conditionLastPlusBottomX[index]"
                      :y2="realBottomY"
                      stroke="#000" stroke-width="2" />
            </svg>
        </div>
    </div>

    <div style="height: 60px"></div>

    <component v-if="this.jsonInfo.next && this.jsonInfo.next !== null" :is="this.jsonInfo.next['type']" :jsonInfo="this.jsonInfo.next" :ref="'commonChildRef'"
               :beforeNode="this.jsonInfo" :beforeNodeStartX="realBottomX" :beforeNodeStartY="realBottomY" :globalJson="globalJson"></component>

    <svg width="0" height="0">
        <defs>
            <marker id="arrow" markerWidth="6" markerHeight="6" refX="0" refY="2" orient="auto">
                <path d="M0,0 L0,4 L6,2 z" fill="#000000" />
            </marker>
        </defs>
    </svg>

    <svg width="100000px" height="100000px" style="position: absolute;z-index: -1; top: 0; left: 0;">
        <line :x1="beforeNodeStartX"
              :y1="beforeNodeStartY"
              :x2="currentPlusTopX"
              :y2="currentPlusTopY"
              stroke="#000" stroke-width="2" />
    </svg>

    <svg width="100000px" height="100000px" style="position: absolute;z-index: -1; top: 0; left: 0;">
        <line :x1="currentPlusBottomX"
              :y1="currentPlusBottomY"
              :x2="currentTopX"
              :y2="currentTopY"
              stroke="#000" stroke-width="2" marker-end="url(#arrow)" />
    </svg>

    <svg width="100000px" height="100000px" style="position: absolute;z-index: -1; top: 0; left: 0;">
        <line :x1="currentBottomX"
              :y1="currentBottomY"
              :x2="currentAddChildPlusTopX"
              :y2="currentAddChildPlusTopY"
              stroke="#000" stroke-width="2"/>
    </svg>

    <svg width="100000px" height="100000px" style="position: absolute;z-index: -1; top: 0; left: 0;">
        <line :x1="currentAddChildPlusBottomX"
              :y1="currentAddChildPlusBottomY"
              :x2="currentAddChildPlusBottomX"
              :y2="currentAddChildPlusBottomY + 20"
              stroke="#000" stroke-width="2"/>
    </svg>

    <svg width="100000px" height="100000px" style="position: absolute;z-index: -1; top: 0; left: 0;">
        <line :x1="conditionLastPlusBottomX[0]"
              :y1="realBottomY"
              :x2="conditionLastPlusBottomX[jsonInfo.childrenNodes.length - 1]"
              :y2="realBottomY"
              stroke="#000" stroke-width="2" />
    </svg>

    <svg width="100000px" height="100000px" style="position: absolute;z-index: -1; top: 0; left: 0;">
        <line :x1="currentChildListTopX[0]"
              :y1="currentChildListTopY[0] - 40"
              :x2="currentChildListTopX[jsonInfo.childrenNodes.length - 1]"
              :y2="currentChildListTopY[jsonInfo.childrenNodes.length - 1] - 40"
              stroke="#000" stroke-width="2" />
    </svg>

    <el-drawer v-model="drawerFlag" :with-header="false" :close-on-click-modal="false" :lock-scroll="true">
        <YwuParallelNodeDrawer :properties="jsonInfo.properties"/>
        <template #footer>
            <div style="flex: auto">
                <el-button @click="cancelUpdate()">取消</el-button>
                <el-button type="primary" @click="confirmUpdate()">确认</el-button>
            </div>
        </template>
    </el-drawer>
</template>

<script>
import {addNodeInfo, getMaxWidth, parseMultiInfo} from "@/utils/flowCommon";
import emitter from "@/utils/mitt";
import YwuParallelNodeDrawer from "@/views/bpmn/flow/drawer/YwuParallelNodeDrawer";

export default {
    name: "YwuParallelNode",
    components: {YwuParallelNodeDrawer},
    props: ["jsonInfo", "beforeNodeStartX", "beforeNodeStartY", "beforeNode", "globalJson"],
    data() {
        return {
            currentTopX: 0,
            currentTopY: 0,
            currentBottomX: 0,
            currentBottomY: 0,
            realBottomX: 0,
            realBottomY: 0,
            currentPlusTopX: 0,
            currentPlusTopY: 0,
            currentPlusBottomX: 0,
            currentPlusBottomY: 0,
            currentAddChildPlusTopX: 0,
            currentAddChildPlusTopY: 0,
            currentAddChildPlusBottomX: 0,
            currentAddChildPlusBottomY: 0,
            currentChildListTopX: [],
            currentChildListTopY: [],
            currentChildListBottomX: [],
            currentChildListBottomY: [],
            lastComponentBottomX: [],
            lastComponentBottomY: [],
            conditionLastPlusTopX: [],
            conditionLastPlusTopY: [],
            conditionLastPlusBottomX: [],
            conditionLastPlusBottomY: [],
            closeShow: false,
            isDelete: false,
            drawerFlag: false,
            propertiesCopy: {}
        }
    },
    methods: {
        calcXy() {
            if (this.isDelete) {
                return;
            }
            this.realBottomY = 0;
            let nodeInfo = this.$refs.currentDiv;
            this.currentTopX = nodeInfo.offsetLeft + nodeInfo.offsetWidth / 2;
            this.currentBottomX = nodeInfo.offsetLeft + nodeInfo.offsetWidth / 2;
            this.currentTopY = nodeInfo.offsetTop - 10;
            this.currentBottomY = nodeInfo.offsetTop + nodeInfo.offsetHeight;
            nodeInfo = this.$refs.currentPlus;
            this.currentPlusTopX = nodeInfo.offsetLeft + nodeInfo.offsetWidth / 2;
            this.currentPlusBottomX = nodeInfo.offsetLeft + nodeInfo.offsetWidth / 2;
            this.currentPlusTopY = nodeInfo.offsetTop;
            this.currentPlusBottomY = nodeInfo.offsetTop + nodeInfo.offsetHeight;
            nodeInfo = this.$refs.addChildNodePlus;
            this.currentAddChildPlusTopX = nodeInfo.offsetLeft + nodeInfo.offsetWidth / 2;
            this.currentAddChildPlusBottomX = nodeInfo.offsetLeft + nodeInfo.offsetWidth / 2;
            this.currentAddChildPlusTopY = nodeInfo.offsetTop;
            this.currentAddChildPlusBottomY = nodeInfo.offsetTop + nodeInfo.offsetHeight;
            // 解析所有子分支节点的位置信息
            for (let index = 0; index < this.jsonInfo.childrenNodes.length; index++) {
                let tempNodeInfo = this.$refs['childNode' + index][0];
                this.currentChildListTopX[index] = tempNodeInfo.offsetLeft + tempNodeInfo.offsetWidth / 2;
                this.currentChildListTopY[index] = tempNodeInfo.offsetTop;
                this.currentChildListBottomX[index] = tempNodeInfo.offsetLeft + tempNodeInfo.offsetWidth / 2;
                this.currentChildListBottomY[index] = tempNodeInfo.offsetTop + tempNodeInfo.offsetHeight;
            }
            // 获取当前分支下的最深处子结点的位置信息
            for (let index = 0; index < this.jsonInfo.childrenNodes.length; index++) {
                nodeInfo = this.$refs['conditionLastPlus' + index][0];
                this.conditionLastPlusTopX[index] = nodeInfo.offsetLeft + nodeInfo.offsetWidth / 2;
                this.conditionLastPlusBottomX[index] = nodeInfo.offsetLeft + nodeInfo.offsetWidth / 2;
                this.conditionLastPlusTopY[index] = nodeInfo.offsetTop;
                this.conditionLastPlusBottomY[index] = nodeInfo.offsetTop + nodeInfo.offsetHeight;
                let item = this.jsonInfo.childrenNodes[index];
                this.realBottomY = this.realBottomY > this.conditionLastPlusBottomY[index] ? this.realBottomY : this.conditionLastPlusBottomY[index] + 30
                if (!item.next) {
                    // 没有挂载其他结点
                    this.lastComponentBottomX[index] = this.currentChildListBottomX[index];
                    this.lastComponentBottomY[index] = this.currentChildListBottomY[index];
                } else {
                    let tempChildRef = this.$refs['childComponentRef' + index][0];
                    // 递归往下获取
                    while (true) {
                        if (!tempChildRef.jsonInfo.next) {
                            tempChildRef.calcXy();
                            this.lastComponentBottomX[index] = tempChildRef.realBottomX;
                            this.lastComponentBottomY[index] = tempChildRef.realBottomY;
                            break;
                        }
                        tempChildRef = tempChildRef.$refs['commonChildRef']
                    }
                }
            }
            this.realBottomX = this.currentPlusTopX
        },
        addNode(nodeType) {
            addNodeInfo(nodeType, this.beforeNode, this.jsonInfo, this.globalJson);
            emitter.emit("refreshLine", "refreshLine");
        },
        mouseEnter() {
            this.closeShow = true
        },
        mouseLeave() {
            this.closeShow = false;
        },
        conditionMouseEnter(item, index) {
            item.isShow = true;
        },
        conditionMouseLeave(item) {
            item.isShow = false;
        },
        deleteNode() {
            this.isDelete = true;
            this.beforeNode.next = this.jsonInfo.next;
            parseMultiInfo(this.globalJson);
            getMaxWidth(this.globalJson);
            emitter.emit("refreshLine", "refreshLine");
        },
        deleteCondition(item, index) {
            // 并行分支至少为两条分支，少于两条不可删除分支
            if (this.jsonInfo.childrenNodes.length <= 2) {
                return;
            }
            // 删除当前分支
            this.jsonInfo.childrenNodes.splice(index, 1);
            // 重新设置名称
            for (let index = 0; index < this.jsonInfo.childrenNodes.length; index++) {
                let info = this.jsonInfo.childrenNodes[index];
                info.conditionName = "并行分支" + (index + 1);
            }
            parseMultiInfo(this.globalJson);
            getMaxWidth(this.globalJson);
            emitter.emit("refreshLine", "refreshLine");
        },
        addChildNodePlus() {
            let info = {
                type: "common",
                conditionName: "并行分支" + (this.jsonInfo.childrenNodes.length + 1),
                next: {
                    type: "YwuApprovalNode",
                    name: "审批人",
                    properties: {}
                }
            }
            this.jsonInfo.childrenNodes.push(info)
            parseMultiInfo(this.globalJson);
            getMaxWidth(this.globalJson);
            emitter.emit("refreshLine", "refreshLine");
        },
        addChildItemNodePlus(nodeType, item) {
            if (item.next) {
                // 遍历到最后一个结点
                let lastNode = item.next
                while (true) {
                    if (!lastNode.next) {
                        break;
                    }
                    lastNode = lastNode.next
                }
                addNodeInfo(nodeType, lastNode, null, this.globalJson);
            } else {
                addNodeInfo(nodeType, item, null, this.globalJson);
            }
            emitter.emit("refreshLine", "refreshLine");
        },
        showDrawer() {
            // 备份数据
            this.propertiesCopy = {...this.jsonInfo.properties}
            this.drawerFlag = true
        },
        confirmUpdate() {
            this.drawerFlag = false;
        },
        cancelUpdate() {
            this.drawerFlag = false;
            // 还原数据
            this.jsonInfo.properties = {...this.propertiesCopy};
        }
    },
    computed: {
        calcChildrenWidth() {
            let res = "margin: 0 auto;"
            if (this.jsonInfo.childrenNodes.length > 0) {
                let width = this.jsonInfo.width * 150 + 100 * (this.jsonInfo.width - 1);
                res += "width :" + width + "px";
            }
            return res;
        }
    },
    mounted() {
        this.$nextTick(() => {
            this.calcXy();
        });
        // 在组件挂载时添加窗口大小改变的监听器
        window.addEventListener('resize', this.calcXy);
        // 接收事件
        emitter.on('refreshLine', (message) => {
            this.$nextTick(() => {
                this.calcXy();
            });
        });
    },
    beforeDestroy() {
        // 在组件销毁前移除监听器，避免内存泄漏
        window.removeEventListener('resize', this.calcXy);
    }
}
</script>

<style scoped lang="less">
.parallelClass {
    width: 150px;
    height: 80px;
    background-color: rgba(252, 238, 2, 0.4);
    border-radius: 10px;
    .innerClass {
        margin-left: 10px;
        .spanClass {
            margin-left: 10px;
            font-weight: bold;
        }
    }
}
.parallelClass:hover{
    cursor: pointer;
}

.plusClass {
    font-size: 30px;
}

.plusClass:hover {
    cursor: pointer;
    color: rgba(4, 85, 248, 0.91);
}

.colSpanClass{
    height: 50px;
    font-size: 20px;
    line-height: 50px;
}

.colSpanClass:hover {
    background-color: #dfe4e7;
    cursor: pointer;
}

.spanNameClass {
    margin-top: 10px;
    display: inline-block;
    width: 140px;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    line-height: 13px;
    font-size: 13px;
}

.closeClass {
    position: absolute;
    top: 10px;
    right: 10px;
    font-size: 15px;
}

.closeClass:hover {
    color: #ee4646;
}

.parallelItemClass {
    display: inline-block;
    vertical-align: top;
    width: 150px;
    margin: 0 auto;
    height: 80px;
    background-color: rgba(252, 238, 2, 0.4);
    border-radius: 10px;
    .innerClass {
        margin-left: 10px;
        .spanClass {
            margin-left: 10px;
            font-weight: bold;
        }
    }
}

.parallelItemClass {
    cursor: pointer;
}
</style>